package com.kk.demo.unsface.two.unsafelist;

import java.lang.reflect.InvocationTargetException;

import com.kk.demo.unsface.two.unsafelist.copy.UnrolledUnsafeCopierBuilder;
import com.kk.demo.unsface.two.unsafelist.copy.UnsafeCopier;
import com.kk.demo.unsface.two.unsafelist.copy.User;

import sun.misc.Unsafe;

/**
 * 进行堆外内存数据结构,连续的内存的数据
* 源文件名：UnsafeArrayList.java
* 文件版本：1.0.0
* 创建作者：liujun
* 创建日期：2016年11月25日
* 修改作者：liujun
* 修改日期：2016年11月25日
* 文件描述：TODO
* 版权所有：Copyright 2016 zjhz, Inc. All Rights Reserved.
*/
public class UnsafeArrayList<T> {

    /**
     * 第一个属性的偏移
    * @字段说明 firstFieldOffset
    */
    private long firstFieldOffset;

    /**
     * 元素大小
    * @字段说明 elementSize
    */
    private long elementSize;

    /**
     * unsafe对象
    * @字段说明 unsafe
    */
    private Unsafe unsafe;

    /**
     * 基本大小
    * @字段说明 base
    */
    private long base;

    /**
     * 类型信息
    * @字段说明 type
    */
    private Class<T> type;

    final UnsafeCopier copier;

    /**
     * 临时交换的变量信息
    * @字段说明 temp
    */
    private T temp;

    /**
     * 初始化创建集合对象
    * 构造方法
    * @param type
    * @param capacity
     * @throws InvocationTargetException 
     * @throws NoSuchMethodException 
     * @throws InstantiationException 
     * @throws IllegalAccessException 
    */
    @SuppressWarnings("unchecked")
    public UnsafeArrayList(Class<T> type, int capacity)
            throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        this.type = type;
        this.firstFieldOffset = UnsafeHelper.firstFieldOffset(type);
        this.elementSize = UnsafeHelper.sizeOf(type) - firstFieldOffset;
        this.unsafe = UnsafeHelper.getUnsafe();
        // 进行内存区域分配，返回起始内存
        base = unsafe.reallocateMemory(base, elementSize * capacity);
        copier = new UnrolledUnsafeCopierBuilder().of(type).build(this.unsafe);
        // 进行临时对象的初始化
        temp = (T) unsafe.allocateInstance(type);

    }

    private long offset(int index) {
        return base + (this.elementSize * index);
    }

    /**
     * 设置堆外内存的数据
    * 方法描述
    * @param index
    * @param element
    * @创建日期 2016年11月25日
    */
    public void set(int index, T element) {
        unsafe.copyMemory(element, firstFieldOffset, null, offset(index), elementSize);
    }

    public void swap(int left, int right) {
        // 将左边的变量记录到临时变量中
        copier.copy(temp, offset(left));
        // 将左变量变为右变量
        unsafe.copyMemory(null, offset(right), null, offset(left), elementSize);
        // 改变左变量的值
        unsafe.copyMemory(temp, firstFieldOffset, null, offset(right), elementSize);
    }

    /**
     * 获取目录索引处的地址信息
    * 方法描述
    * @param dest
    * @param index
    * @return
    * @创建日期 2016年11月25日
    */
    public T get(T dest, int index) {
        // ,得到对象的地址

        // unsafe.copyMemory(null, offset(index), dest, firstFieldOffset,
        // elementSize);
        copier.copy(dest, offset(index));
        // 获取数组中的对象信息
        return dest;
    }

    /**
     * 获取目录索引信息
    * 方法描述
    * @param index
    * @return
     * @throws InstantiationException 
    * @创建日期 2016年11月25日
    */
    @SuppressWarnings("unchecked")
    public T get(int index) throws InstantiationException {
        return get((T) unsafe.allocateInstance(type), index);
    }

    /**
     * 获取属性的偏移
    * 方法描述
    * @param field
    * @return
    * @throws Exception
    * @创建日期 2016年12月1日
    */
    public long getObjectOffset(String field) throws Exception {
        return unsafe.objectFieldOffset(type.getDeclaredField(field)) - firstFieldOffset;
    }

    public int compleValue(int left, int right, long objectOffset) throws Exception {

        // 获取到对象的地址
        int leftValue = unsafe.getInt(offset(left) + objectOffset);

        int rightValue = unsafe.getInt(offset(right) + objectOffset);

        if (leftValue > rightValue) {
            return 1;
        }

        else if (leftValue < rightValue) {
            return -1;
        }

        return 0;
    }

    /**
     * 进行倒排
    * 方法描述
    * @param left
    * @param right
    * @param objectOffset
    * @return
    * @throws Exception
    * @创建日期 2016年12月1日
    */
    public int compleValueOrderDesc(int left, int right, long objectOffset) throws Exception {

        // 获取到对象的地址
        int leftValue = unsafe.getInt(offset(left) + objectOffset);

        int rightValue = unsafe.getInt(offset(right) + objectOffset);

        if (leftValue < rightValue) {
            return 1;
        }

        else if (leftValue > rightValue) {
            return -1;
        }

        return 0;
    }

    public static void main(String[] args) throws Exception {
        UnsafeArrayList<User> unsafeArray = new UnsafeArrayList<User>(User.class, 10);

        unsafeArray.set(0, new User(0, 10));
        unsafeArray.set(1, new User(1, 20));
        unsafeArray.set(2, new User(2, 30));

        long objSet = unsafeArray.getObjectOffset("age");

        unsafeArray.compleValue(1, 2, objSet);

        try {
            System.out.println(unsafeArray.get(0));
            unsafeArray.swap(0, 1);
            System.out.println(unsafeArray.get(0));
            System.out.println(unsafeArray.get(1));
            System.out.println(unsafeArray.get(2));
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

}
